`include "defines.v"
module ysyx_210448_exe_stage(
  input clk,
  input wire rst,
  input wire exe_mem_read,
  input wire mem_mem_read,
  input wire r_hs,
  input wire [63:0] p_exe_op1,
  input wire [63:0] p_exe_op2,
  input wire p_ready1,
  input wire p_ready2,
  input wire [3:0]axi_r_id_i,
  input wire exe_fetched,
  input reg [63:0]exe_op1,
  input reg [63:0]exe_op2,
  input wire [4 : 0]exe_rd,
  input reg [63:0]exe_pc,
  input reg [31:0] exe_inst,
  input wire [6:0] exe_opcode,
  input wire [19 : 0]exe_u_imm,
  input wire [19 : 0]exe_j_imm,
  input wire [11 : 0]exe_j_imm_j,
  input wire [11 : 0]exe_i_imm,
  input wire [6 : 0]exe_b_imm,
  input wire [6 : 0]exe_s_imm,
  input wire [4 : 0]exe_s_imm_s,
  input wire [4 : 0]exe_i_imm_i,
  input wire [11 : 0]exe_I_imm,
  input wire [11:0]exe_w_imm,
  input wire [5:0]exe_w_shamt,
  input wire [5:0]shamt,
  input wire [4:0] exe_b_imm_b,
  input wire [2:0] exe_s1,
  input wire exe_s2,
  input reg [63:0]exe_t,
  input reg [4:0]exe_zimm,
  output reg [63:0]exe_csr_data_re,
  output reg [`REG_BUS] exe_data_re,
  input wire exe_w_ena,
  output wire exe_skip,
  output wire exe_pc_write,
  output wire [63:0] exe_pc_add_re,
  output reg exe_mem_en,
  output reg if_id_bubble,
  output reg id_exe_bubble,
  output reg mem_read,
  output reg [2:0] s3,
  output wire [7:0] io_uart_out_ch,
  output wire io_uart_out_valid
);
//处理后的立即数
wire [63:0] exe_u_imm_u;
wire [63:0] exe_b_imm_b_b_b;
wire [11:0] exe_b_imm_b_b;
wire [19:0] jal_imm;
wire [11:0]s_s;
wire imm1;
wire [7:0] imm2;
wire imm3;
wire [9:0] imm4;
wire [5:0]imm5;
wire [3:0]imm6;
wire [5:0]sra_imm;
wire [4:0]sra_imm_w;
wire [4:0]sll_imm;
wire [5:0]sll_imm_sll;
wire [5:0]srl_imm;
wire [4:0]srl_imm_w;
wire [63:0]sllw;
wire [31:0]srlw;
wire [31:0]sraw;
wire [7:0] printf;
wire [63:0]csr_zimm;
wire [63:0] mepc_reserve;
//assign exe_pc_add=((exe_opcode==7'b1100011)||(exe_opcode==7'b1101111)||(exe_opcode==7'b1100111))?pc_add:64'b0;
//assign exe_pc_write=((exe_opcode==7'b1100011)||(exe_opcode==7'b1101111)||(exe_opcode==7'b1100111))?pc_write:0;
assign exe_skip=(exe_opcode==7'b1111011)?1'b1:1'b0;//difftest跳过信号
assign io_uart_out_valid=((exe_fetched)&&(exe_opcode==7'b1111011))?1:0;
assign exe_mem_en=1'b1;
assign sll_imm_sll=exe_op2[5:0];
assign srl_imm=exe_op2[5:0];
assign sra_imm=exe_op2[5:0];
assign printf=exe_data[7:0];
assign csr_zimm={{59{1'b0}},exe_zimm[4:0]};
assign imm2=exe_j_imm[7:0];
assign imm5=exe_b_imm[5:0];
assign imm4=exe_j_imm[18:9];
assign imm6=exe_b_imm_b[4:1];
assign sll_imm=exe_op2[4:0];
assign sllw=exe_op1<<sll_imm;
assign srl_imm_w=exe_op2[4:0];
assign sra_imm_w=exe_op2[4:0];
assign exe_b_imm_b_b={imm1,imm3,imm5,imm6};
assign exe_b_imm_b_b_b=({{52{exe_b_imm_b_b[11]}},exe_b_imm_b_b})<<1;
assign exe_u_imm_u=({{44{exe_u_imm[19]}},exe_u_imm})<<12;
assign jal_imm=({imm3,imm2,imm1,imm4})<<1;
assign io_uart_out_ch=((exe_opcode==7'b1111011)&&(exe_fetched))?exe_data_re[7:0]:0;
assign imm3=(exe_opcode==7'b1101111)?exe_j_imm[19]:exe_b_imm_b[0];
assign imm1=(exe_opcode==7'b1101111)?exe_j_imm[8]:exe_b_imm[6];
assign srlw=(exe_opcode==7'b0111011)?exe_op1[31:0]>>srl_imm_w:
                                     exe_op1[31:0]>>exe_w_shamt;
assign sraw=(exe_opcode==7'b0111011)?(($signed(exe_op1[31:0]))>>>sra_imm_w):
                                       (($signed(exe_op1[31:0]))>>>exe_w_shamt);
//wire [63:0] exe_u_imm_lui=({{44{exe_u_imm[19]}},exe_u_imm})<<12;
wire [63:0] exe_data_w_add=e_op1+{{52{exe_w_imm[11]}},exe_w_imm};
wire [63:0] exe_data_w_slli=e_op1<<exe_w_shamt;
wire [63:0] exe_data_addw=e_op1+e_op2;
wire [63:0] exe_data_w_sub=e_op1-e_op2;
wire [63:0] e_op1;
wire [63:0] e_op2;
assign e_op1=(p_ready1)?p_exe_op1:exe_op1;
assign e_op2=(p_ready2)?p_exe_op2:exe_op2;

reg [63:0] exe_pc_add;
reg [63:0] exe_csr_data;
reg [63:0] exe_data;

always @(posedge clk) begin
  if(rst) begin
  exe_csr_data_re<=64'b0;
  exe_data_re<=64'b0;
  exe_pc_add_re<=64'b0;
  end
  else if(exe_fetched)
  begin
    exe_csr_data_re<=exe_csr_data;
    exe_data_re<=exe_data;
    exe_pc_add_re<=exe_pc_add;
    if(exe_pc_add_re[0]==1'b1)
    begin
      exe_pc_add_re[0]<=1'b0;
    end
  end
end



always@(*)
begin
  if(rst)
  begin
  exe_csr_data =`ZERO_WORD;
  exe_data=`ZERO_WORD;
  //exe_data_w=`YSYX210448_ZERO_WORD;
  exe_pc_write=1'b0;
  exe_pc_add=`ZERO_WORD;
  end
  else //if(exe_fetched)
  begin
  exe_pc_write=1'b0;
  exe_pc_add=64'b0;
  exe_csr_data=64'b0;
  exe_data=64'b0;
  if(exe_opcode==7'b0110011)
  begin
    exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
    exe_data=64'b0;
      if(exe_s2==0) begin
      if(exe_s1==3'b000)  exe_data=e_op1+e_op2; //add 
      else if(exe_s1==3'b001) begin  exe_data=e_op1<<sll_imm_sll;end //sll
      else if(exe_s1==3'b010) exe_data=($signed(e_op2)>$signed(e_op1))?1:0;////slt
      else if(exe_s1==3'b011) exe_data=($unsigned(e_op2)>$unsigned(e_op1))?1:0;//sltu
      else if(exe_s1==3'b100) exe_data=e_op1^e_op2;//xor
      else if(exe_s1==3'b101) begin exe_data=e_op1>>srl_imm; end//exe_op1右移exe_op2，空位填0,srl
      else if(exe_s1==3'b110) exe_data=e_op1|e_op2;//or
      else if(exe_s1==3'b111) exe_data=e_op1&e_op2;//and
      else exe_data=64'b0;
      end
    else begin
      if(exe_s1==3'b00) exe_data=e_op1-e_op2;//sub
      else if(exe_s1==3'b101) begin exe_data=($signed(e_op1))>>>sra_imm;end//exe_op1右移exe_op2,空位用exe_op1最高位填充,sra
      else exe_data=64'b0;
    end
  end
  else if(exe_opcode==7'b0010011)
  begin
    exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
    exe_data=64'b0;
    if(exe_s1==3'b000) begin exe_data=e_op1+{{52{exe_i_imm[11]}},exe_i_imm};end//addi
    else if(exe_s1==3'b010) exe_data=($signed(e_op1)<$signed({{52{exe_i_imm[11]}},exe_i_imm}))?1:0;//slit 
    else if(exe_s1==3'b011) exe_data=($unsigned(e_op1)<$unsigned({{52{exe_i_imm[11]}},exe_i_imm}))?1:0;//slitu
    else if(exe_s1==3'b100) exe_data=e_op1^{{52{exe_i_imm[11]}},exe_i_imm};//xori
    else if(exe_s1==3'b110) exe_data=e_op1|{{52{exe_i_imm[11]}},exe_i_imm};//ori
    else if(exe_s1==3'b111) exe_data=e_op1&{{52{exe_i_imm[11]}},exe_i_imm};//andi
    else if(exe_s1==3'b001) exe_data=e_op1<<shamt;//slli
    else if(exe_s1==3'b101) begin  if(exe_s2==0) begin exe_data=e_op1>>shamt; end
    else begin exe_data=($signed(e_op1))>>>shamt; end end
    else exe_data=64'b0;
  end
  else if(exe_opcode==7'b1100011)
  begin
    exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
    exe_data=64'b0;
    if(exe_s1==3'b000) begin  exe_pc_add=(e_op1==e_op2)?exe_b_imm_b_b_b+exe_pc:exe_pc+4;
    exe_pc_write=(e_op1==e_op2)?1:0; end//beq
    else if(exe_s1==3'b001) begin exe_pc_add=(e_op1!=e_op2)?exe_b_imm_b_b_b+exe_pc:exe_pc+4;
    exe_pc_write=(e_op1!=e_op2)?1:0; end//bne
    else if(exe_s1==3'b100) begin exe_pc_add=($signed(e_op1)<$signed(e_op2))?exe_b_imm_b_b_b+exe_pc:exe_pc+4;
    exe_pc_write=($signed(e_op1)<$signed(e_op2))?1:0; end//blt
    else if(exe_s1==3'b101) begin exe_pc_add=($signed(e_op1)>=$signed(e_op2))?exe_b_imm_b_b_b+exe_pc:exe_pc+4;
    exe_pc_write=($signed(e_op1)>=$signed(e_op2))?1:0; end
    else if(exe_s1==3'b110) begin  exe_pc_add=($unsigned(e_op1)<$unsigned(e_op2))?exe_b_imm_b_b_b+exe_pc:exe_pc+4;
    exe_pc_write=($unsigned(e_op1)<$unsigned(e_op2))?1:0; end
    else if(exe_s1==3'b111) begin exe_pc_add=($unsigned(e_op1)>=$unsigned(e_op2))?exe_b_imm_b_b_b+exe_pc:exe_pc+4;
    exe_pc_write=($unsigned(e_op1)>=$unsigned(e_op2))?1:0; end
    else begin exe_pc_add=64'b0;exe_pc_write=1'b0; end
  end
  else if(exe_opcode==7'b0110111)
  begin
   exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
    //exe_u_imm_lui={{44{exe_u_imm[19]}},exe_u_imm};
    //exe_u_imm_lui=exe_u_imm_u<<12;
    exe_data=exe_u_imm_u;//lui
  end
  else if(exe_opcode==7'b0010111)
  begin
    exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
    //exe_u_imm_u={{44{exe_u_imm[19]}},exe_u_imm};
    //exe_u_imm_u=exe_u_imm_u<<12;
    exe_data=exe_u_imm_u+exe_pc;//auiexe_pc
  end
  else if(exe_opcode==7'b1101111)
  begin
    exe_csr_data=64'b0;
    exe_data=exe_pc+4;
    //imm1=exe_j_imm[8];
    //imm2=exe_j_imm[7:0];
    //imm3=exe_j_imm[19];
    //imm4=exe_j_imm[18:0];
    //jal_imm={imm3,imm2,imm1,imm4};
    //jal_imm=jal_imm<<1;
    exe_pc_add={{44{jal_imm[19]}},jal_imm}+exe_pc;
    exe_pc_write=1'b1;//jal
  end
  else if(exe_opcode==7'b1100111)
  begin
    exe_csr_data=64'b0;
    exe_data=exe_pc+4;
    exe_pc_add=e_op1+{{52{exe_j_imm_j[11]}},exe_j_imm_j};//&(~1);
    //if(exe_pc_add[0]==1'b1)
    //begin
      //exe_pc_add[0]=1'b0;
    //end
    exe_pc_write=1'b1;//jalr
    
  end
  else if(exe_opcode==7'b0011011)
  begin
    exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
    exe_data=64'b0;
    if(exe_s1==3'b000) begin //exe_data_w_add=e_op1+{{52{exe_w_imm[11]}},exe_w_imm};
    exe_data={{32{exe_data_w_add[31]}},exe_data_w_add[31:0]};end//addiw
    else if(exe_s1==3'b101) begin if(exe_s2==1'b0) begin exe_data={{32{srlw[31]}},srlw};end//srliw
    else begin exe_data={{32{sraw[31]}},sraw[31:0]}; end end//sraiw
    else if(exe_s1==3'b001) begin 
    exe_data={{32{exe_data_w_slli[31]}},exe_data_w_slli[31:0]};end//slliw
    else exe_data=64'b0;
  end
  else if(exe_opcode==7'b0111011)
  begin
    exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
    exe_data=64'b0;
    if(exe_s2==1'b0) begin
      if(exe_s1==3'b000) begin exe_data={{32{exe_data_addw[31]}},exe_data_addw[31:0]}; end//addw
      else if(exe_s1==3'b001) begin exe_data={{32{sllw[31]}},sllw[31:0]}; end//sllw
      else if(exe_s1==3'b101) begin exe_data={{32{srlw[31]}},srlw};end//srlw
      else exe_data=64'b0;
    end
    else begin
      if(exe_s1==3'b000) begin exe_data={{32{exe_data_w_sub[31]}},exe_data_w_sub[31:0]};end//subw
      else if(exe_s1==3'b101) begin exe_data={{32{sraw[31]}},sraw[31:0]};end //sraw
      else exe_data=64'b0;
    end
  end
  else if(exe_opcode==7'b1110011)
  begin
    exe_pc_write=1'b0;
     exe_pc_add=64'b0;
     exe_csr_data=64'b0;
     exe_data=exe_t;
     //csr_zimm={{59{1'b0}},exe_zimm[4:0]};
     if(exe_s1==3'b001) exe_csr_data=e_op1;
     else if(exe_s1==3'b010) exe_csr_data=exe_t|e_op1;
     else if(exe_s1==3'b011) exe_csr_data=(exe_t)&(~e_op1);
     else if(exe_s1==3'b101) exe_csr_data=csr_zimm;
     else if(exe_s1==3'b110) exe_csr_data=exe_t|csr_zimm;
     else if(exe_s1==3'b111) exe_csr_data=(exe_t)&(~csr_zimm);
     else exe_csr_data=64'b0;
  end
  else
  begin
    //exe_mem_bubble=1'b0;
    exe_data=64'b0;
    exe_pc_write=1'b0;
    exe_pc_add=64'b0;
    exe_csr_data=64'b0;
  end
 end
end

 wire mem_read_open=(exe_mem_read)?((mem_mem_read)?0:1):0;
wire [63:0] exe_mem_read_addr;
assign exe_mem_read_addr=e_op1+{{52{exe_I_imm[11]}},exe_I_imm};
always @(posedge clk) begin
  if(rst)
  begin
    mem_read<=1'b0;
    s3<=3'b0;
  end
  else
  begin
  if(mem_read_open)
  begin
    mem_read<=1'b1;
    s3<=exe_mem_read_addr[2:0];
  end
  else if(r_hs&&axi_r_id_i==4'b0010)
  begin
    mem_read<=1'b0;
  end
  else
  begin
    mem_read<=mem_read;
    s3<=s3;
  end
  end
  
end
endmodule

